/*
 *    Copyright 2010-2015 the original author or authors.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */

package cn.powertime.evaluation.shiro;

import cn.powertime.evaluation.shiro.cacho.RedisCacheManager;
import cn.powertime.evaluation.shiro.filter.JwtAuthenticationFilter;
import com.google.common.collect.Maps;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.mgt.DefaultSecurityManager;
import org.apache.shiro.mgt.DefaultSessionStorageEvaluator;
import org.apache.shiro.mgt.DefaultSubjectDAO;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.realm.Realm;
import org.apache.shiro.session.mgt.DefaultSessionManager;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.filter.DelegatingFilterProxy;

import javax.servlet.Filter;
import java.util.LinkedHashMap;
import java.util.Map;

/**
 * @author ZYW
 */
@Configuration
public class ShiroConfiguration {

    private final static Logger LOGGER = LoggerFactory.getLogger(ShiroConfiguration.class);

    @Bean(name = "realm")
    @DependsOn("lifecycleBeanPostProcessor")
    public Realm jwtRealm() {
        return new JwtRealm();
    }

    @Bean
    public JwtAuthenticationFilter jwtAuthenticationFilter() {
        return new JwtAuthenticationFilter();
    }

    @Bean
    public FilterRegistrationBean delegatingFilterProxy() {
        FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
        DelegatingFilterProxy proxy = new DelegatingFilterProxy();
        proxy.setTargetFilterLifecycle(true);
        proxy.setTargetBeanName("shiroFilter");
        filterRegistrationBean.setFilter(proxy);
        return filterRegistrationBean;
    }

    @Bean(name = "shiroFilter")
    @DependsOn("securityManager")
    public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) {

        ShiroFilterFactoryBean shiroFilter = new ShiroFilterFactoryBean();
        shiroFilter.setSecurityManager(securityManager);
        shiroFilter.setLoginUrl("");
        shiroFilter.setSuccessUrl("");
        shiroFilter.setUnauthorizedUrl("");

        //拦截器
        LinkedHashMap<String, String> filterChainDefinitionMap = Maps.newLinkedHashMap();

        //filterChainDefinitionMap.put("/treeTable.jspx","jwt");
        //filterChainDefinitionMap.put("/get.jspx", "jwt");

        filterChainDefinitionMap.put("/auth/login", "anon");
        filterChainDefinitionMap.put("/app/auth/login", "anon");
        filterChainDefinitionMap.put("/auth/captcha*", "anon");

        //用户
        filterChainDefinitionMap.put("/web/user/updatePwd", "jwt");
        filterChainDefinitionMap.put("/web/user/update/account", "jwt");
        filterChainDefinitionMap.put("/web/user/edit", "jwt");

        //资源播放
        // filterChainDefinitionMap.put("/file/video/**", "jwt");



        filterChainDefinitionMap.put("/auth/token/refresh", "jwt");
        //上传接口需要认证
        // filterChainDefinitionMap.put("/file/upload", "jwt");
        filterChainDefinitionMap.put("/dict/**", "jwt");
        filterChainDefinitionMap.put("/dict/type/**", "jwt");
        filterChainDefinitionMap.put("/res/**", "jwt");
        filterChainDefinitionMap.put("/role/**", "jwt");
        filterChainDefinitionMap.put("/sysLog/**", "jwt");
        filterChainDefinitionMap.put("/sysSafeStrategy/**", "jwt");
        filterChainDefinitionMap.put("/sysuser/**", "jwt");

        //课程接口
        filterChainDefinitionMap.put("/web/cps-course/courseResourceList", "jwt");
        filterChainDefinitionMap.put("/web/cps-course/record", "jwt");
        filterChainDefinitionMap.put("/web/cps-course/recordList", "jwt");
       // filterChainDefinitionMap.put("/app/cps-course/courseResourceList", "jwt");
       // filterChainDefinitionMap.put("/app/cps-course/record", "jwt");
       // filterChainDefinitionMap.put("/app/cps-course/recordList", "jwt");

        //pc帖子
        filterChainDefinitionMap.put("/web/dbq-postings/add", "jwt");
        filterChainDefinitionMap.put("/web/dbq-postings/event", "jwt");
        filterChainDefinitionMap.put("/web/dbq-postings/comment", "jwt");
        filterChainDefinitionMap.put("/web/dbq-postings/postingsEvent", "jwt");

        //app帖子
        filterChainDefinitionMap.put("/app/dbq-postings/add", "jwt");
        filterChainDefinitionMap.put("/app/dbq-postings/event", "jwt");
        filterChainDefinitionMap.put("/app/dbq-postings/comment", "jwt");
        filterChainDefinitionMap.put("/app/dbq-postings/postingsEvent", "jwt");

        //试卷接口
        filterChainDefinitionMap.put("/web/testPaper/**", "jwt");
       // filterChainDefinitionMap.put("/app/testPaper/**", "jwt");
        //收藏习题接口
        filterChainDefinitionMap.put("/web/userCollect/**", "jwt");
        filterChainDefinitionMap.put("/app/userCollect/**", "jwt");
        //我的关注接口
        filterChainDefinitionMap.put("/web/focus/**", "jwt");
        filterChainDefinitionMap.put("/app/focus/**", "jwt");
        //个人中心接口
        filterChainDefinitionMap.put("/web/personalCenter/**", "jwt");
        filterChainDefinitionMap.put("/app/personalCenter/**", "jwt");

        //APP搜索接口
        filterChainDefinitionMap.put("/app/user/editLion", "jwt");
        filterChainDefinitionMap.put("/app/user/userInfoApp", "jwt");
        filterChainDefinitionMap.put("/app/user/remove", "jwt");
        filterChainDefinitionMap.put("/app/search/**", "jwt");
        filterChainDefinitionMap.put("/app/user/edit", "jwt");
        filterChainDefinitionMap.put("/app/cps-course/**", "jwt");
        filterChainDefinitionMap.put("/app/cirle/**", "jwt");
        filterChainDefinitionMap.put("/app/cps-credit/**", "jwt");
        filterChainDefinitionMap.put("/app/dbq-news/**", "jwt");
        filterChainDefinitionMap.put("/app/dbq-question/**", "jwt");
        filterChainDefinitionMap.put("/app/testPaper/**", "jwt");

        filterChainDefinitionMap.put("/get.jspx", "jwt");
        filterChainDefinitionMap.put("/del.jspx", "jwt");
        filterChainDefinitionMap.put("/mod.jspx", "jwt");
        filterChainDefinitionMap.put("/add.jspx", "jwt");

        filterChainDefinitionMap.put("/**", "anon");


        shiroFilter.setFilterChainDefinitionMap(filterChainDefinitionMap);

        Map<String, Filter> filterMap = Maps.newHashMap();
        filterMap.put("jwt", jwtAuthenticationFilter());

        shiroFilter.setFilters(filterMap);

        return shiroFilter;
    }


    /**
     * 保证实现了Shiro内部lifecycle函数的bean执行
     */
    @Bean(name = "lifecycleBeanPostProcessor")
    public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
        return new LifecycleBeanPostProcessor();
    }


    @Bean(name = "securityManager")
    public DefaultSecurityManager securityManager(Realm realm, RedisCacheManager redisCacheManager) {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setRealm(realm);

//        用自己的Factory实现替换默认用于关闭session功能
        securityManager.setSubjectFactory(new StatelessSubjectFactory());
        securityManager.setSessionManager(sessionManager());

//        关闭session存储
        ((DefaultSessionStorageEvaluator) ((DefaultSubjectDAO) securityManager.getSubjectDAO()).getSessionStorageEvaluator()).setSessionStorageEnabled(false);

//        <!-- 用户授权/认证信息Cache缓存 -->
        securityManager.setCacheManager(redisCacheManager);

        SecurityUtils.setSecurityManager(securityManager);

        return securityManager;
    }

    @Bean
    public DefaultSessionManager sessionManager() {
        DefaultSessionManager manager = new DefaultSessionManager();
        // 关闭session定时检查
        manager.setSessionValidationSchedulerEnabled(false);
        return manager;
    }

    @Bean
    @DependsOn("lifecycleBeanPostProcessor")
    public DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
        defaultAdvisorAutoProxyCreator.setProxyTargetClass(true);
        return defaultAdvisorAutoProxyCreator;
    }

    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAdvisor(SecurityManager securityManager) {
        AuthorizationAttributeSourceAdvisor authorizationAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAdvisor.setSecurityManager(securityManager);
        return authorizationAdvisor;
    }

    @Bean
    public RedisCacheManager redisCacheManager(RedisTemplate redisTemplate) {
        return new RedisCacheManager(redisTemplate);
    }

}
